home *** CD-ROM | disk | FTP | other *** search
/ Celestin Apprentice 5 / Apprentice-Release5.iso / Source Code / C / Applications / Moscow ML 1.31 / source code / mosml / src / mosmllib / Polyhash.sml < prev    next >
Encoding:
Text File  |  1996-07-03  |  7.6 KB  |  272 lines  |  [TEXT/R*ch]

  1. (* Modified for Moscow ML from SML/NJ Library version 0.2
  2.  *
  3.  * COPYRIGHT (c) 1992 by AT&T Bell Laboratories.
  4.  * See file mosml/copyrght/copyrght.att for details.
  5.  *
  6.  * Original author: John Reppy, AT&T Bell Laboratories, Murray Hill, NJ 07974
  7.  *)
  8.  
  9. datatype ('key, 'data) bucket_t
  10.   = NIL
  11.   | B of int * 'key * 'data * ('key, 'data) bucket_t
  12.  
  13. datatype ('key, 'data) hash_table = 
  14.     HT of {hashVal   : 'key -> int,
  15.        sameKey   : 'key * 'key -> bool,
  16.        not_found : exn,
  17.        table     : ('key, 'data) bucket_t Array.array ref,
  18.        n_items   : int ref}
  19.  
  20. local 
  21.     prim_val andb_      : int -> int -> int = 2 "and";
  22.     prim_val lshift_    : int -> int -> int = 2 "shift_left";
  23. in 
  24.     fun index (i, sz) = andb_ i (sz-1)
  25.  
  26.   (* find smallest power of 2 (>= 32) that is >= n *)
  27.     fun roundUp n = 
  28.     let fun f i = if (i >= n) then i else f (lshift_ i 1)
  29.     in f 32 end
  30. end;
  31.  
  32.   (* Create a new table; the int is a size hint and the exception
  33.    * is to be raised by find.
  34.    *)
  35.     fun mkTable (hashVal, sameKey) (sizeHint, notFound) = HT{
  36.             hashVal=hashVal,
  37.         sameKey=sameKey,
  38.         not_found = notFound,
  39.         table = ref (Array.array(roundUp sizeHint, NIL)),
  40.         n_items = ref 0
  41.       };
  42.  
  43.   (* conditionally grow a table *)
  44.     fun growTable (HT{table, n_items, ...}) = let
  45.         val arr = !table
  46.         val sz = Array.length arr
  47.         in
  48.           if (!n_items >= sz)
  49.         then let
  50.           val newSz = sz+sz
  51.           val newArr = Array.array (newSz, NIL)
  52.           fun copy NIL = ()
  53.             | copy (B(h, key, v, rest)) = let
  54.             val indx = index (h, newSz)
  55.             in
  56.               Array.update (newArr, indx,
  57.                 B(h, key, v, Array.sub(newArr, indx)));
  58.               copy rest
  59.             end
  60.           fun bucket n = (copy (Array.sub(arr, n)); bucket (n+1))
  61.           in
  62.             (bucket 0) handle _ => ();
  63.             table := newArr
  64.           end
  65.         else ()
  66.         end (* growTable *);
  67.  
  68.   (* Insert an item.  If the key already has an item associated with it,
  69.    * then the old item is discarded.
  70.    *)
  71.     fun insert (tbl as HT{hashVal, sameKey, table, n_items, ...}) (key, item) =
  72.     let
  73.       val arr = !table
  74.       val sz = Array.length arr
  75.       val hash = hashVal key
  76.       val indx = index (hash, sz)
  77.       fun look NIL = (
  78.         Array.update(arr, indx, B(hash, key, item, Array.sub(arr, indx)));
  79.         n_items := !n_items + 1;
  80.         growTable tbl;
  81.         NIL)
  82.         | look (B(h, k, v, r)) = if ((hash = h) andalso sameKey(key, k))
  83.         then B(hash, key, item, r)
  84.         else (case (look r)
  85.            of NIL => NIL
  86.             | rest => B(h, k, v, rest)
  87.           (* end case *))
  88.       in
  89.         case (look (Array.sub (arr, indx)))
  90.          of NIL => ()
  91.           | b => Array.update(arr, indx, b)
  92.       end;
  93.  
  94.   (* find an item, the table's exception is raised if the item doesn't exist *)
  95.     fun find (HT{hashVal, sameKey, table, not_found, ...}) key = let
  96.       val arr = !table
  97.       val sz = Array.length arr
  98.       val hash = hashVal key
  99.       val indx = index (hash, sz)
  100.       fun look NIL = raise not_found
  101.         | look (B(h, k, v, r)) = if ((hash = h) andalso sameKey(key, k))
  102.         then v
  103.         else look r
  104.       in
  105.         look (Array.sub (arr, indx))
  106.       end;
  107.  
  108.   (* look for an item, return NONE if the item doesn't exist *)
  109.     fun peek (HT{hashVal, sameKey, table, ...}) key = let
  110.       val arr = !table
  111.       val sz = Array.length arr
  112.       val hash = hashVal key
  113.       val indx = index (hash, sz)
  114.       fun look NIL = NONE
  115.         | look (B(h, k, v, r)) = if ((hash = h) andalso sameKey(key, k))
  116.         then SOME v
  117.         else look r
  118.       in
  119.         look (Array.sub (arr, indx))
  120.       end;
  121.  
  122.   (* Remove an item.  The table's exception is raised if
  123.    * the item doesn't exist.
  124.    *)
  125.     fun remove (HT{hashVal, sameKey, not_found, table, n_items}) key = let
  126.       val arr = !table
  127.       val sz = Array.length arr
  128.       val hash = hashVal key
  129.       val indx = index (hash, sz)
  130.       fun look NIL = raise not_found
  131.         | look (B(h, k, v, r)) = if ((hash = h) andalso sameKey(key, k))
  132.         then (v, r)
  133.         else let val (item, r') = look r in (item, B(h, k, v, r')) end
  134.       val (item, bucket) = look (Array.sub (arr, indx))
  135.       in
  136.         Array.update (arr, indx, bucket);
  137.         n_items := !n_items - 1;
  138.         item
  139.       end (* remove *);
  140.  
  141.   (* Return the number of items in the table *)
  142.    fun numItems (HT{n_items, ...}) = !n_items
  143.  
  144.   (* return a list of the items in the table *)
  145.     fun listItems (HT{table = ref arr, n_items, ...}) = let
  146.       fun f (_, l, 0) = l
  147.         | f (~1, l, _) = l
  148.         | f (i, l, n) = let
  149.         fun g (NIL, l, n) = f (i-1, l, n)
  150.           | g (B(_, k, v, r), l, n) = g(r, (k, v)::l, n-1)
  151.         in
  152.           g (Array.sub(arr, i), l, n)
  153.         end
  154.       in
  155.         f ((Array.length arr) - 1, [], !n_items)
  156.       end (* listItems *);
  157.  
  158.   (* Apply a function to the entries of the table *)
  159.     fun apply f (HT{table, ...}) = let
  160.       fun appF NIL = ()
  161.         | appF (B(_, key, item, rest)) = (
  162.         f (key, item);
  163.         appF rest)
  164.       val arr = !table
  165.       val sz = Array.length arr
  166.       fun appToTbl i = if (i < sz)
  167.         then (appF (Array.sub (arr, i)); appToTbl(i+1))
  168.         else ()
  169.       in
  170.         appToTbl 0
  171.       end (* apply *);
  172.  
  173.   (* Map a table to a new table that has the same keys and exception *)
  174.     fun map f (HT{hashVal, sameKey, table, n_items, not_found}) = let
  175.       fun mapF NIL = NIL
  176.         | mapF (B(hash, key, item, rest)) =
  177.         B(hash, key, f (key, item), mapF rest)
  178.       val arr = !table
  179.       val sz = Array.length arr
  180.       val newArr = Array.array (sz, NIL)
  181.       fun mapTbl i = if (i < sz)
  182.         then (
  183.           Array.update(newArr, i, mapF (Array.sub(arr, i)));
  184.           mapTbl (i+1))
  185.         else ()
  186.       in
  187.         mapTbl 0;
  188.         HT{hashVal=hashVal,
  189.            sameKey=sameKey,
  190.            table = ref newArr, 
  191.            n_items = ref(!n_items), 
  192.            not_found = not_found}
  193.       end (* transform *);
  194.  
  195.   (* remove any hash table items that do not satisfy the given
  196.    * predicate.
  197.    *)
  198.     fun filter pred (HT{table, n_items, not_found, ...}) = let
  199.       fun filterP NIL = NIL
  200.         | filterP (B(hash, key, item, rest)) = if (pred(key, item))
  201.         then B(hash, key, item, filterP rest)
  202.         else filterP rest
  203.       val arr = !table
  204.       val sz = Array.length arr
  205.       fun filterTbl i = if (i < sz)
  206.         then (
  207.           Array.update (arr, i, filterP (Array.sub (arr, i)));
  208.           filterTbl (i+1))
  209.         else ()
  210.       in
  211.         filterTbl 0
  212.       end (* filter *);
  213.  
  214.   (* Map a table to a new table that has the same keys, exception,
  215.      hash function, and equality function *)
  216.  
  217.     fun transform f (HT{hashVal, sameKey, table, n_items, not_found}) = let
  218.       fun mapF NIL = NIL
  219.         | mapF (B(hash, key, item, rest)) = B(hash, key, f item, mapF rest)
  220.       val arr = !table
  221.       val sz = Array.length arr
  222.       val newArr = Array.array (sz, NIL)
  223.       fun mapTbl i = if (i < sz)
  224.         then (
  225.           Array.update(newArr, i, mapF (Array.sub(arr, i)));
  226.           mapTbl (i+1))
  227.         else ()
  228.       in
  229.         mapTbl 0;
  230.         HT{hashVal=hashVal, 
  231.            sameKey=sameKey, 
  232.            table = ref newArr, 
  233.            n_items = ref(!n_items), 
  234.            not_found = not_found}
  235.       end (* transform *);
  236.  
  237.   (* Create a copy of a hash table *)
  238.     fun copy (HT{hashVal, sameKey, table, n_items, not_found}) = let
  239.       val arr = !table
  240.       val sz = Array.length arr
  241.       val newArr = Array.array (sz, NIL)
  242.       fun mapTbl i = (
  243.         Array.update (newArr, i, Array.sub(arr, i));
  244.         mapTbl (i+1))
  245.       in
  246.         (mapTbl 0) handle _ => ();
  247.         HT{hashVal=hashVal, 
  248.            sameKey=sameKey,
  249.            table = ref newArr, 
  250.            n_items = ref(!n_items), 
  251.            not_found = not_found}
  252.       end (* copy *);
  253.  
  254.   (* returns a list of the sizes of the various buckets.  This is to
  255.    * allow users to gauge the quality of their hashing function.
  256.    *)
  257.     fun bucketSizes (HT{table = ref arr, ...}) = let
  258.       fun len (NIL, n) = n
  259.         | len (B(_, _, _, r), n) = len(r, n+1)
  260.       fun f (~1, l) = l
  261.         | f (i, l) = f (i-1, len (Array.sub (arr, i), 0) :: l)
  262.       in
  263.         f ((Array.length arr)-1, [])
  264.       end
  265.  
  266. prim_val hash_param : int -> int -> 'a -> int = 3 "hash_univ_param";
  267.  
  268. fun hash x = hash_param 50 500 x;
  269.  
  270. fun mkPolyTable (sizeHint, notFound) = 
  271.      mkTable (hash, op=) (sizeHint, notFound);
  272.